#pragma once
#include <memory>
#include <string>
#include <iostream>

#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include "Log.hpp"
#include "Socket.hpp"

const static int defualtport = 8888;
const static int defualtbacklog = 8;
const static int num = sizeof(fd_set) * 8;

using namespace Net_Work;

class SelectServer
{
private:
    void HandlerEvent(fd_set &rfds)
    {
        // 遍历数组，找到合法就绪fd
        for (int i = 0; i < num; i++)
        {
            if (!_rfd_array[i])
                continue;

            int fd = _rfd_array[i]->GetSockfd();
            // 检测事件是否就绪
            if (FD_ISSET(fd, &rfds))
            {
                if (fd == _listensock->GetSockfd())
                {
                    lg.LogMessage(Info, "get a new link");

                    // 获取新连接,需要阻塞吗？不需要，因为OS条件已经就绪
                    uint16_t client_port;
                    std::string client_ip;
                    Socket *sock = _listensock->AcceptConnection(&client_ip, &client_port);
                    if (!sock)
                    {
                        lg.LogMessage(Error, "accept error");
                        return;
                    }
                    lg.LogMessage(Info, "get a new client... client_ip:%s,client_port:%d", client_ip.c_str(), client_port);

                    // 不能直接read write,因为数据可能没有就绪，交给数组托管
                    int pos = 0;
                    for (; pos < num; pos++)
                    {
                        if (!_rfd_array[pos])
                        {
                            _rfd_array[pos] = sock;
                            lg.LogMessage(Info, "get a new link ,fd is:%d", sock->GetSockfd());
                            break;
                        }
                    }
                    if (pos == num)
                    {
                        sock->CloseSockFd();
                        delete sock;
                        lg.LogMessage(Error, "server if full!!");
                    }
                }
                // 普通事件
                else
                {
                    std::string inbuffer;
                    bool ret = _rfd_array[i]->Recv(&inbuffer, 1024);
                    if (ret)
                    {
                        lg.LogMessage(Info, "client say#%s", inbuffer.c_str());
                        inbuffer += ":server Recv!";
                        _rfd_array[i]->Send(inbuffer);
                        inbuffer.clear();
                    }
                    else
                    {
                        // 读取失败 和客户端断开
                        lg.LogMessage(Warning, "client broken! maybe client quit or error!");
                        _rfd_array[i]->CloseSockFd();
                        delete _rfd_array[i];
                        _rfd_array[i] = nullptr;
                    }
                }
            }
        }
    }

public:
    SelectServer(int port = defualtport)
        : _port(port), _isrunning(false), _listensock(new TcpSocket())
    {
    }

    void InitServer()
    {
        _listensock->BuildListenSocketMethod(_port, defualtbacklog);
        // 初始的fd为listen套接字
        for (int i = 0; i < num; i++)
        {
            _rfd_array[i] = nullptr;
        }
        _rfd_array[0] = _listensock.get();
    }

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 不能直接accept ,需要交给select
            // 位图
            fd_set rfds;
            FD_ZERO(&rfds);
            FD_SET(_listensock->GetSockfd(), &rfds);

            // select
            // 每隔五秒非阻塞询问
            struct timeval timeout
            {
                5, 0
            };

            int max_fd = _listensock->GetSockfd();
            // 对n讨论
            // 遍历数组，找到合法的fd
            for (int i = 0; i < num; i++)
            {
                if (_rfd_array[i])
                {
                    int fd = _rfd_array[i]->GetSockfd();
                    FD_SET(fd, &rfds);
                    if (max_fd < fd)
                        max_fd = fd;
                }
                else
                    continue;
            }
            int n = select(max_fd + 1, &rfds, nullptr, nullptr, &timeout);
            switch (n)
            {
            // 超时
            case 0:

                lg.LogMessage(Info, "select timeout...,last time:%u.%u", timeout.tv_sec, timeout.tv_usec);
                break;

            // 等待失败
            case -1:

                lg.LogMessage(Error, "select error ");
                break;
            // 正常等待
            default:
            {
                // 条件就绪，执行hander,调用connect
                lg.LogMessage(Info, "select success!begin event handler...last time:%u.%u", timeout.tv_sec, timeout.tv_usec);
                HandlerEvent(rfds);
                break;
            }
            }
        }
        _isrunning = false;
    }

private:
    std::unique_ptr<Socket> _listensock;
    int _port;
    int _isrunning;

    // 需要管理所有的fd
    Socket *_rfd_array[num];
};